原本爬蟲是用curl的PHP方式在爬,但是某些網站它的資料是靠JS產生的導致第一時間沒辦法抓到應該要有的網頁
本篇會把抓下來的資料寫入excel,接下來直接進入實作的部分:
工具
1.chromedriver(簡易版的 chrome 瀏灠器)
下載位置
composer require facebook/webdriver
3.library:phpoffice (操作excel)
composer require phpoffice/phpexcel
程式碼:
//引用
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\WebDriverCapabilityType;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\WebDriverBy;
---------------------------------
// 創建 ChromeOptions 實例
$options = new ChromeOptions();
$options->addArguments(['--headless']); //背景執行
$serverUrl='http://localhost:9515'; //chromedriver的服務要開啟才能使用
$capabilities = DesiredCapabilities::chrome();
$capabilities->setCapability(ChromeOptions::CAPABILITY, $options);
$driver = RemoteWebDriver::create( $serverUrl, $capabilities);
$web='https://shopee.tw';
// 訪問蝦皮網站並獲取頁面元素
$driver->get($web);
sleep(3); //蝦皮的頁面要等一下 資料才會跑完
//蝦皮防機器人跳轉判斷
$url = $driver->getCurrentURL();
//
....
....
....
//
$List = $driver->findElement(WebDriverBy::className('shop-search-result-view'));
$element = $List->findElements(WebDriverBy::tagName('a'));
$link=$element->getAttribute('href');
// 關閉瀏覽器
$driver->quit();
瀏覽器測試 (Laravel Dusk),似乎能做到自動開啟,
搜尋元素說明:
$driver->findElement //獲取單個元素,只會抓取第一個
$driver->findElements //獲取元素列表
WebDriverBy 搜尋方法
WebDriverBy::id($id) 使用 ID 查找元素
WebDriverBy::className($className) 使用 class 查找元素
WebDriverBy::cssSelector($selctor) 使用 css 選擇器查詢
WebDriverBy::name($name) 使用元素的 name 查詢
WebDriverBy::linkText($text) 使用元素的文本查詢
WebDriverBy::tagName($tagName) 使用元素標簽查詢 (EX: span、a、img..之類)
WebDriverBy::xpath($xpath) 根据 xpath 表達式查詢 (我比較愛用這個,直接指定路徑,蝦皮class是亂數,好難抓...)
元素資料分析
$element->getAttribute('href'); //a link的網址 ,也能獲取其它屬性 (ex:type ,class,id...標簽內的所有屬性)
$element->getAttribute('innerHTML') //元素內的頁面
$element->getText(); //只抓取文字
$path='"//span/parent::div/following-sibling::div[2]";'
try{
$data=$List->findElement(WebDriverBy::xpath($path'))->getText();
}catch(NoSuchElementException $e){
$data=null;
}
//$waitSeconds =15 ; 建議設定15秒以內
$driver->wait($waitSeconds)->until(
WebDriverExpectedCondition::visibilityOfElementLocated(
WebDriverBy::xpath($path')
)
);
$data=$List->findElement(WebDriverBy::xpath($path'))->getText();
//父元素下所有的路徑 /父元素下的下一個路徑 /parent::div/following-sibling 父元素的兄弟節點
在搜尋元素時記得要用做try catch,找不到元素會直接報錯,就跳停。不然就要使用wait等待,有些網頁元素出現是不一定會有的,就用try catch找,依情況使用不同的方法。
網頁元素操作:
//輸入框
$element = $driver->findElement(WebDriverBy::id('web_id'));
$element->sendKeys("test"); //在輸入框中輸入内容'test'
$element->clear(); //将输入框清空
$element->getAttribute('value'); //獲取輸入框内容
//單選框
$radio = $driver->findElement(WebDriverBy::id('web_radio')); //
$radio->click(); //選擇某個單選項
$radio->isSelected(); //判斷選項是否被選擇
3.多選框
$checkbox = $driver->findElement(WebDriverBy::id('web_checkbox'));
$checkbox->click(); //選擇某個選項
$checkbox->isSelected(); //判斷選項是否被選擇
$checkbox->isEnabled(); //判斷是否enable
4.下拉框
//PS.下拉框要定位兩次,第一次先找位置第二次在抓value
$select = $driver->findElement(WebDriverBy::id('web_select'));
$select->findElement(WebDriverBy::xpath("//option[@value='aa']"))->click(); //點選下拉aa的選項
5.按鈕
$btn = $driver->findElement(WebDriverBy::id('web_btn'));
$btn->click(); //點擊按鈕
$btn->isEnabled(); //判斷是否enable
6.文件上傳
$upload = $driver->findElement(WebDriverBy::id('web_upload'));
$filePath = "C:\檔案上傳\\test.jpg";
$upload->sendKeys($filePath);
Excel 寫入
//引用
use PhpOffice\PhpSpreadsheet\Calculation\Category;
use PhpOffice\PhpSpreadsheet\IOFactory; //excel操作
use PhpOffice\PhpSpreadsheet\Reader\Xlsx; //2007讀取
----------------
$file = storage_path('app/public/excel/product_xls_demo.xlsx');
$newFile = storage_path('app/public/excel/複製檔案.Xlsx');
if (!copy($file, $newFile)) {
die("複製檔案失敗.");
}
// 讀取 Excel 文件
$objReader = IOFactory::createReader('Xlsx'); //這邊參數請使用Xlsx , 大小寫有差別
$objPHPExcel = $objReader->load($newFile);
// 选择工作表
$objPHPExcel->setActiveSheetIndex(0);
$sheet = $objPHPExcel->getActiveSheet();
$i=1;//初始位置
foreach( $value_set['style_detail'] as $value){
$objPHPExcel->getActiveSheet()
->setCellValue('A'.$i, $value_set['product'] )
->setCellValue('B'.$i, in_array($value_set['brand'],$brand_validation)?$value_set['brand']:'自有品牌')
->setCellValue('C'.$i, $value_set['category1'] )
->setCellValue('D'.$i, $value_set['category2'])
->setCellValue('E'.$i, $value_set['category3'] )
->setCellValue('F'.$i, 0)
->setCellValue('G'.$i, '一般商品')
->setCellValue('H'.$i, $value_set['spec'])
->setCellValue('I'.$i, $value_set['style1_name'])
->setCellValue('J'.$i, $value['style1'] )
->setCellValue('K'.$i, $value_set['style2_name'])
->setCellValue('L'.$i, $value['style2'] )
->setCellValue('M'.$i, $value['offer'] )
->setCellValue('N'.$i, $value['sp_offer']??$value['offer'])
->setCellValue('O'.$i, $value['style_num'] )
// ->setCellValue('P'.$i, $value[''] )
->setCellValue('Q'.$i, 'omg_p'.time())
->setCellValue('R'.$i, $value_set['detail'])
->setCellValue('S'.$i, $value_set['web_url']);
$i++;
}
// 保存 Excel 文件
$objWriter = IOFactory::createWriter($objPHPExcel, 'Xlsx');
$objWriter->save($newFile);
//下載excel檔案
header('Content-type:application/vnd.ms-excel'); //宣告網頁格式
header('Content-Disposition: attachment; filename='.$file_name); //$file_name 是變數,代表要下載的 Excel 檔案名稱。
header("Pragma: no-cache");
header("Expires: 0");//這兩行程式碼主要是告訴瀏覽器不要快取下載的檔案,以確保使用者下載到的是最新版本。
$objWriter->save('php://output');//輸出到網頁中。
exit;
本篇做基礎的爬蟲,還有很多爬蟲會遇到的問題,像是機器人驗證或是區塊被擋住無法點擊的問題都是有可能會遇到的